package com.sora.transport.socket.client;

import com.caucho.hessian.io.Serializer;
import com.sora.loadbalancer.LoadBalancer;
import com.sora.loadbalancer.RandomLoadBalancer;
import com.sora.registry.NacosServiceDiscovery;
import com.sora.registry.NacosServiceRegistry;
import com.sora.registry.ServiceDiscovery;
import com.sora.registry.ServiceRegistry;
import com.sora.transport.RpcClient;
import com.sora.entity.RpcRequest;
import com.sora.entity.RpcResponse;
import com.sora.enumeration.RpcError;
import com.sora.exception.RpcException;
import com.sora.serializer.CommonSerializer;
import com.sora.util.ObjectReader;
import com.sora.util.ObjectWriter;
import com.sora.util.RpcMessageChecker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;

/**
 * @Classname: RpcClient
 * @Description:
 * @Author: Stonffe
 * @Date: 2023/4/29 14:40
 */

public class SocketClient implements RpcClient {
    private static final Logger logger = LoggerFactory.getLogger(SocketClient.class);
    private final ServiceDiscovery serviceDiscovery;
    private final CommonSerializer serializer;
    public SocketClient() {
        this(DEFAULT_SERIALIZER, new RandomLoadBalancer());
    }
    public SocketClient(Integer serializer) {
        this(serializer, new RandomLoadBalancer());
    }
    public SocketClient(LoadBalancer loadBalancer) {
        this(DEFAULT_SERIALIZER, loadBalancer);
    }
    public SocketClient(Integer serializer, LoadBalancer loadBalancer) {
        serviceDiscovery = new NacosServiceDiscovery(loadBalancer);
        this.serializer = CommonSerializer.getByCode(serializer);
    }
    @Override
    public Object sendRequest(RpcRequest rpcRequest) {
        if(serializer == null) {
            logger.error("未设置序列化器");
            throw new RpcException(RpcError.SERIALIZER_NOT_FOUND);
        }
        InetSocketAddress address = serviceDiscovery.lookupService(rpcRequest.getInterfaceName());
        try (Socket socket = new Socket()) {
            socket.connect(address);
            InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream();
            ObjectWriter.writeObject(outputStream,rpcRequest,serializer);
            Object o = ObjectReader.readObject(inputStream);
            RpcResponse rpcResponse = (RpcResponse) o;
            if (rpcResponse == null) {
                logger.error("服务调用失败，service：{}", rpcRequest.getInterfaceName());
                throw new RpcException(RpcError.SERVICE_INVOCATION_FAILURE, " service:" + rpcRequest.getInterfaceName());
            }
            RpcMessageChecker.check(rpcRequest, rpcResponse);
            return rpcResponse;
        } catch (IOException e ) {
            logger.error("调用时有错误发生：",e);
            throw new RpcException("服务调用失败: ", e);
        }
    }

}
